'''手写数字识别项目'''

import numpy as np
import cv2
import operator

#1.处理图片
def createDataset():
    train_dataset=[]       #训练数据                 #用cv2加载图片速度快
    for i in range(10):
        for j in range(1,401):  #左闭右开
            digit1=cv2.imread('data/%d/%d_%d.bmp' % (i,i,j))  #格式化读入数据 注意：j的起始数字是1
            digit1 = digit1[:, :, 0]            #将三维降为二维，减少数据量
            digit1 = np.asarray(digit1)         #将数据转为numpy对象便于操作
            train_dataset.append(digit1.ravel())  #将每一个二维矩阵展开变为一维向量，便于后面运算
    train_dataset=np.asarray(train_dataset)

    test_dataset = []      #测试数据
    for i in range(10):
        for j in range(401, 501):
            digit2 = cv2.imread('data/%d/%d_%d.bmp' % (i, i, j))
            digit2=digit2[:, :, 0]
            digit2 = np.asarray(digit2)
            test_dataset.append(digit2.ravel())
    test_dataset = np.asarray(test_dataset)

    train_lableset=[]      #训练标签
    for i in range(10):
        for j in range(1,401):
            train_lableset.append(i)
    train_lableset = np.asarray(train_lableset)

    test_lableset = []     #测试标签
    for i in range(10):
        for j in range(401, 501):
            test_lableset.append(i)
    test_lableset = np.asarray(test_lableset)
    #print(test_lableset)

    return train_dataset,train_lableset,test_dataset,test_lableset

#2.编写分类器
def classify(inx,dataSet,labels,k):  #inx:输入向量
    datasetSize=dataSet.shape[0]  #计算训练样本个数

    #(1)计算测试样本和训练样本之间的距离——用欧式距离
    diffMat=np.tile(inx,(datasetSize,1))-dataSet  #分别算差
    sqDiffMat=diffMat**2  #分别平方
    sqDistances=sqDiffMat.sum(axis=1)  #按行相加
    distances=sqDistances**0.5  #开方

    #(2)将算出的距离排序
    sortedDistance=distances.argsort()  #得到排序后的下标

    #(3)算出前K个样本中每种类别出现的次数
    classCount={}  #定义一个字典存放类别和类别的频率
    for i in range(k):
        voteLabel=labels[sortedDistance[i]]  #分别通过下标取出标签
        classCount[voteLabel]=classCount.get(voteLabel,0)+1  #将标签和次数存入classCount字典里
        #get(voteLabel,0)的意思是，若key存在，得到key的值；若key不存在，得到0

    #(4)将classCount的内容按值排序，选出出现次数最多的标签
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1))
    return sortedClassCount[0][0]


if __name__=='__main__':
    train_dataset,train_lableset,test_dataset,test_lableset=createDataset()  #处理数据
    '''验证标签和数据是否对应
    index=np.random.randint(0,1000,size=1)[0]
    digit=test_dataset[index]
    print('标签为：-------------',test_lableset[index])
    plt.imshow(digit,cmap="gray")
    plt.show()
    '''
    error=0
    sum=0
    for i in range(1000):                                             #将数据放入分类函数
        test=classify(test_dataset[i], train_dataset, train_lableset, 1)    #k=1时错误率最低
        print('实际算出的标签为：',test,'             正确的标签为：',test_lableset[i])
        if test!=test_lableset[i]:
            error=error+1
        sum=sum+1
    print('\n'"总样本数为",sum)
    print("错误的个数为：",error,'         错误率为：',error/1000,'    ',error/10,'%')
